package team.bluepen.supermarket.data.entity;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import team.bluepen.supermarket.kafka.KafkaDeserializer;
import team.bluepen.supermarket.kafka.KafkaSerializer;

import java.beans.ConstructorProperties;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * @author RollW
 */
public class ProductIdNamesAmount implements Serializable {
    @JsonProperty("id")
    private final long id;

    @JsonProperty("amounts")
    private final HashMap<String, ProductNameStatusAmount> amounts;

    @ConstructorProperties({"id", "amounts"})
    public ProductIdNamesAmount(long id, HashMap<String, ProductNameStatusAmount> amounts) {
        this.id = id;
        this.amounts = amounts;
    }

    public ProductIdNamesAmount(long id) {
        this.id = id;
        this.amounts = new HashMap<>();
    }

    public long getId() {
        return id;
    }

    public ProductIdNamesAmount put(ProductNameStatusAmount amount) {
        amounts.put(amount.getName(), amount);
        return this;
    }

    public ProductIdNamesAmount put(Product product) {
        amounts.put(product.getName(), ProductNameStatusAmount.of(product));
        return this;
    }

    public Map<String, ProductNameStatusAmount> getAmounts() {
        return amounts;
    }

    public ProductNameStatusAmount getAmount(String name) {
        return amounts.get(name);
    }

    public static ProductIdNamesAmount add(ProductIdNamesAmount a, ProductIdNamesAmount b) {
        HashMap<String, ProductNameStatusAmount> map = new HashMap<>(a.getAmounts());
        b.getAmounts().forEach((k, v) -> {
            if (map.containsKey(k)) {
                map.put(k, ProductNameStatusAmount.add(map.get(k), v));
            } else {
                map.put(k, v);
            }
        });
        return new ProductIdNamesAmount(a.getId(), map);
    }

    public static KafkaSerializer<ProductIdNamesAmount> serializer() {
        return Serial.INSTANCE;
    }

    public static KafkaDeserializer<ProductIdNamesAmount> deserializer() {
        return Serial.INSTANCE;
    }

    private static class Serial implements KafkaSerializer<ProductIdNamesAmount>, KafkaDeserializer<ProductIdNamesAmount> {
        private final ObjectMapper objectMapper = new ObjectMapper();

        @Override
        public ProductIdNamesAmount deserialize(String data) {
            try {
                return objectMapper.readValue(data, ProductIdNamesAmount.class);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public String serialize(ProductIdNamesAmount productIdNamesAmount) {
            try {
                return objectMapper.writeValueAsString(productIdNamesAmount);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }

        private static final Serial INSTANCE = new Serial();
    }

}
